home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / nt / source.exe / POSIX / CP / CP.C next >
C/C++ Source or Header  |  1993-06-23  |  19KB  |  809 lines

  1. /*
  2.  * Copyright (c) 1988 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * This code is derived from software contributed to Berkeley by
  6.  * David Hitz of Auspex Systems Inc.
  7.  *
  8.  * Redistribution and use in source and binary forms, with or without
  9.  * modification, are permitted provided that the following conditions
  10.  * are met:
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer.
  13.  * 2. Redistributions in binary form must reproduce the above copyright
  14.  *    notice, this list of conditions and the following disclaimer in the
  15.  *    documentation and/or other materials provided with the distribution.
  16.  * 3. All advertising materials mentioning features or use of this software
  17.  *    must display the following acknowledgement:
  18.  *    This product includes software developed by the University of
  19.  *    California, Berkeley and its contributors.
  20.  * 4. Neither the name of the University nor the names of its contributors
  21.  *    may be used to endorse or promote products derived from this software
  22.  *    without specific prior written permission.
  23.  *
  24.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34.  * SUCH DAMAGE.
  35.  */
  36.  
  37. #ifdef DF_POSIX /* DF_MSS */
  38. #include <misc.h>
  39. #include <bsdlib.h>
  40. #endif
  41.  
  42. #ifndef lint
  43. char copyright[] =
  44. "@(#) Copyright (c) 1988 The Regents of the University of California.\n\
  45.  All rights reserved.\n";
  46. #endif /* not lint */
  47.  
  48. #ifndef lint
  49. static char sccsid[] = "@(#)cp.c    5.24 (Berkeley) 5/6/91";
  50. #endif /* not lint */
  51.  
  52. /*
  53.  * cp copies source files to target files.
  54.  * 
  55.  * The global PATH_T structures "to" and "from" always contain paths to the
  56.  * current source and target files, respectively.  Since cp does not change
  57.  * directories, these paths can be either absolute or dot-realative.
  58.  * 
  59.  * The basic algorithm is to initialize "to" and "from", and then call the
  60.  * recursive copy() function to do the actual work.  If "from" is a file,
  61.  * copy copies the data.  If "from" is a directory, copy creates the
  62.  * corresponding "to" directory, and calls itself recursively on all of
  63.  * the entries in the "from" directory.
  64.  */
  65. #ifdef _POSIX_SOURCE
  66. #else
  67. #include <sys/param.h>
  68. #endif
  69. #include <sys/stat.h>
  70. #ifdef _POSIX_SOURCE
  71. #include <time.h>
  72. #else
  73. #include <sys/time.h>
  74. #endif
  75. #include <dirent.h>
  76. #include <fcntl.h>
  77. #include <errno.h>
  78. #include <unistd.h>
  79. #include <stdio.h>
  80. #include <stdlib.h>
  81. #include <string.h>
  82. #include "cp.h"
  83.  
  84. PATH_T from = { from.p_path, "" };
  85. PATH_T to = { to.p_path, "" };
  86.  
  87. uid_t myuid;
  88. int exit_val;
  89. mode_t myumask;
  90. int iflag, pflag, orflag, rflag;
  91. int (*statfcn) __P((const char *, struct stat *));
  92. char *buf, *progname;
  93.  
  94. void copy __P((void));
  95. void copy_file __P((struct stat *, int));
  96. void copy_dir __P((void));
  97. void copy_link __P((int));
  98. void copy_fifo __P((struct stat *, int));
  99. void copy_special __P((struct stat *, int));
  100. void setfile __P((register struct stat *, int));
  101. void error __P((const char *));
  102. void usage __P((void));
  103.  
  104. #if WIN_NT
  105. extern int globulate __P((int, int, char **));
  106. extern void deglobulate __P((void));
  107. extern int globulated_argc;
  108. extern char **globulated_argv;
  109. pid_t ppid;
  110. int globulation;
  111. #endif
  112.  
  113. int
  114. #if __STDC__
  115. main (int argc, char **argv)
  116. #else
  117. main(argc, argv)
  118.     int argc;
  119.     char **argv;
  120. #endif
  121. {
  122.     extern int optind;
  123.     struct stat to_stat;
  124.     register int c, r;
  125. #if WIN_NT
  126. #else
  127.     int symfollow, lstat(), stat();
  128. #endif
  129.     char *old_to, *p;
  130.  
  131.     /*
  132.      * The utility cp(1) is used by mv(1) -- except for usage statements,
  133.      * print the "called as" program name.
  134.      */
  135. #if WIN_NT
  136.     ppid = getppid();
  137.     if (ppid == (pid_t) 1) /* if parent is CMD.EXE */
  138.     {
  139.         globulation = globulate(1, argc, argv);
  140.         if (globulation == 0)
  141.         {
  142.             argc = globulated_argc;
  143.             argv = globulated_argv;
  144. # if 0
  145.             for (c = 0; c < argc; ++c)
  146.                 (void) printf("[%s] ", argv[c]);
  147.             (void) printf("NULL\n");
  148. # endif
  149.         }
  150.     }
  151. #endif
  152.     progname = ((p = rindex(*argv,'/')) != NULL) ? ++p : *argv;
  153.  
  154. #if WIN_NT
  155. #else
  156.     symfollow = 0;
  157. #endif
  158.     while ((c = getopt(argc, argv, "Rfipr")) != EOF) {
  159.     switch ((char)c) {
  160.         case 'f':
  161.             iflag = 0;
  162.             break;
  163. #if WIN_NT
  164. #else
  165.         case 'h':
  166.             symfollow = 1;
  167.             break;
  168. #endif
  169.         case 'i':
  170.             iflag = isatty(fileno(stdin));
  171.             break;
  172.         case 'p':
  173.             pflag = 1;
  174.             break;
  175.         case 'R':
  176.             rflag = 1;
  177.             break;
  178.         case 'r':
  179.             orflag = 1;
  180.             break;
  181.         case '?':
  182.         default:
  183.             usage();
  184.             break;
  185.         }
  186.     }
  187.     argc -= optind;
  188.     argv += optind;
  189.  
  190.     if (argc < 2)
  191.         usage();
  192.  
  193.     if (rflag && orflag) {
  194.         (void)fprintf(stderr,
  195.             "cp: the -R and -r options are mutually exclusive.\n");
  196. #if WIN_NT
  197.         if (ppid == (pid_t) 1 && globulation == 0)
  198.             deglobulate();
  199. #endif
  200.         exit(EXIT_FAILURE);
  201.     }
  202.  
  203.     buf = (char *)malloc(MAXBSIZE);
  204.     if (!buf) {
  205.         (void)fprintf(stderr, "%s: out of space.\n", progname);
  206. #if WIN_NT
  207.         if (ppid == (pid_t) 1 && globulation == 0)
  208.             deglobulate();
  209. #endif
  210.         exit(EXIT_FAILURE);
  211.     }
  212.  
  213.     myuid = getuid();
  214.  
  215.     /* copy the umask for explicit mode setting */
  216.     myumask = umask(0);
  217.     (void)umask(myumask);
  218.  
  219.     /* consume last argument first. */
  220.     if (!path_set(&to, argv[--argc])) {
  221. #if WIN_NT
  222.         if (ppid == (pid_t) 1 && globulation == 0)
  223.             deglobulate();
  224. #endif
  225.         exit(EXIT_FAILURE);
  226.     }
  227.  
  228. #if WIN_NT
  229.     statfcn = stat;
  230. #else
  231.     statfcn = symfollow || !rflag ? stat : lstat;
  232. #endif
  233.  
  234.     /*
  235.      * Cp has two distinct cases:
  236.      *
  237.      * % cp [-rip] source target
  238.      * % cp [-rip] source1 ... directory
  239.      *
  240.      * In both cases, source can be either a file or a directory.
  241.      *
  242.      * In (1), the target becomes a copy of the source. That is, if the
  243.      * source is a file, the target will be a file, and likewise for
  244.      * directories.
  245.      *
  246.      * In (2), the real target is not directory, but "directory/source".
  247.      */
  248.  
  249.     r = stat(to.p_path, &to_stat);
  250.     if (r == -1 && errno != ENOENT) {
  251. #if 0
  252. (void) fprintf(stderr, "#1\n");
  253. #endif
  254.         error(to.p_path);
  255. #if WIN_NT
  256.         if (ppid == (pid_t) 1 && globulation == 0)
  257.             deglobulate();
  258. #endif
  259.         exit(EXIT_FAILURE);
  260.     }
  261.     if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
  262.         /*
  263.          * Case (1).  Target is not a directory.
  264.          */
  265.         if (argc > 1)
  266.             usage();
  267.         if (!path_set(&from, *argv)) {
  268. #if WIN_NT
  269.             if (ppid == (pid_t) 1 && globulation == 0)
  270.                 deglobulate();
  271. #endif
  272.             exit(EXIT_FAILURE);
  273.         }
  274.         copy();
  275.     }
  276.     else {
  277.         /*
  278.          * Case (2).  Target is a directory.
  279.          */
  280.         for (;; ++argv) {
  281.             if (!path_set(&from, *argv)) {
  282.                 exit_val = EXIT_FAILURE;
  283.                 continue;
  284.             }
  285.             old_to = path_append(&to, path_basename(&from), -1);
  286.             if (!old_to) {
  287.                 exit_val = EXIT_FAILURE;
  288.                 continue;
  289.             }
  290.             copy();
  291.             if (!--argc)
  292.                 break;
  293.             path_restore(&to, old_to);
  294.         }
  295.     }
  296. #if WIN_NT
  297.     if (ppid == (pid_t) 1 && globulation == 0)
  298.         deglobulate();
  299. #endif
  300.     return exit_val;
  301. }
  302.  
  303. /* copy file or directory at "from" to "to". */
  304. void
  305. #if __STDC__
  306. copy (void)
  307. #else
  308. copy()
  309. #endif
  310. {
  311.     struct stat from_stat, to_stat;
  312.     int dne, statval;
  313.  
  314.     statval = statfcn(from.p_path, &from_stat);
  315.     if (statval == -1) {
  316. #if 0
  317. (void) fprintf(stderr, "#2\n");
  318. #endif
  319.         error(from.p_path);
  320.         return;
  321.     }
  322.  
  323.     /* not an error, but need to remember it happened */
  324.     if (stat(to.p_path, &to_stat) == -1)
  325.         dne = 1;
  326.     else {
  327.         if (to_stat.st_dev == from_stat.st_dev &&
  328.             to_stat.st_ino == from_stat.st_ino) {
  329.             (void)fprintf(stderr,
  330.                 "%s: %s and %s are identical (not copied).\n",
  331.                 progname, to.p_path, from.p_path);
  332.             exit_val = EXIT_FAILURE;
  333.             return;
  334.         }
  335.         dne = 0;
  336.     }
  337.  
  338.     switch(from_stat.st_mode & S_IFMT) {
  339. #ifndef _POSIX_SOURCE /* DF_MSS */
  340.     case S_IFLNK:
  341.         copy_link(!dne);
  342.         return;
  343. #endif
  344.     case S_IFDIR:
  345.         if (!rflag && !orflag) {
  346.             (void)fprintf(stderr,
  347.                 "%s: %s is a directory (not copied).\n",
  348.                 progname, from.p_path);
  349.             exit_val = EXIT_FAILURE;
  350.             return;
  351.         }
  352.         if (dne) {
  353.             /*
  354.              * If the directory doesn't exist, create the new
  355.              * one with the from file mode plus owner RWX bits,
  356.              * modified by the umask.  Trade-off between being
  357.              * able to write the directory (if from directory is
  358.              * 555) and not causing a permissions race.  If the
  359.              * umask blocks owner writes cp fails.
  360.              */
  361.             if (mkdir(to.p_path, from_stat.st_mode|S_IRWXU) < 0) {
  362. #if 0
  363. (void) fprintf(stderr, "#3\n");
  364. #endif
  365.                 error(to.p_path);
  366.                 return;
  367.             }
  368.         }
  369.         else if (!S_ISDIR(to_stat.st_mode) != S_IFDIR) {
  370.             (void)fprintf(stderr, "%s: %s: not a directory.\n",
  371.                 progname, to.p_path);
  372.             return;
  373.         }
  374.         copy_dir();
  375.         /*
  376.          * If not -p and directory didn't exist, set it to be the
  377.          * same as the from directory, umodified by the umask;
  378.          * arguably wrong, but it's been that way forever.
  379.          */
  380.         if (pflag)
  381.             setfile(&from_stat, 0);
  382.         else if (dne)
  383.             (void)chmod(to.p_path, from_stat.st_mode);
  384.         return;
  385.     case S_IFCHR:
  386.     case S_IFBLK:
  387.         if (rflag) {
  388.             copy_special(&from_stat, !dne);
  389.             return;
  390.         }
  391.         break;
  392.     case S_IFIFO:
  393.         if (rflag) {
  394.             copy_fifo(&from_stat, !dne);
  395.             return;
  396.         }
  397.         break;
  398.     }
  399.     copy_file(&from_stat, dne);
  400. }
  401.  
  402. void
  403. #if __STDC__
  404. copy_file (struct stat *fs, int dne)
  405. #else
  406. copy_file(fs, dne)
  407.     struct stat *fs;
  408.     int dne;
  409. #endif
  410. {
  411.     register int from_fd, to_fd, rcount, wcount;
  412.     struct stat to_stat;
  413.  
  414.     if ((from_fd = open(from.p_path, O_RDONLY, 0)) == -1) {
  415. #if 0
  416. (void) fprintf(stderr, "#4\n");
  417. #endif
  418.         error(from.p_path);
  419.         return;
  420.     }
  421.  
  422.     /*
  423.      * If the file exists and we're interactive, verify with the user.
  424.      * If the file DNE, set the mode to be the from file, minus setuid
  425.      * bits, modified by the umask; arguably wrong, but it makes copying
  426.      * executables work right and it's been that way forever.  (The
  427.      * other choice is 666 or'ed with the execute bits on the from file
  428.      * modified by the umask.)
  429.      */
  430. #if 0
  431. (void) fprintf(stderr, "dne: %d; to.p_path: \"%s\"; fs->st_mode: %lo\n",
  432.     dne, to.p_path, (unsigned long) (fs->st_mode & ~(S_ISUID|S_ISGID)));
  433. #endif
  434.     if (!dne) {
  435.         if (iflag) {
  436.             int checkch, ch;
  437.  
  438.             (void)fprintf(stderr, "overwrite %s? ", to.p_path);
  439.             checkch = ch = getchar();
  440.             while (ch != '\n' && ch != EOF)
  441.                 ch = getchar();
  442.             if (checkch != 'y') {
  443.                 (void)close(from_fd);
  444.                 return;
  445.             }
  446.         }
  447.         to_fd = open(to.p_path, O_WRONLY|O_TRUNC, 0);
  448.     } else
  449.         to_fd = open(to.p_path, O_WRONLY|O_CREAT|O_TRUNC,
  450.             fs->st_mode & ~(S_ISUID|S_ISGID));
  451.  
  452.     if (to_fd == -1) {
  453. #if 0
  454. int saved_errno;
  455.  
  456. saved_errno = errno;
  457. (void) fprintf(stderr, "#5; errno: %d\n", saved_errno);
  458. #endif
  459.         error(to.p_path);
  460.         (void)close(from_fd);
  461.         return;
  462.     }
  463.  
  464.     while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
  465.         wcount = write(to_fd, buf, rcount);
  466.         if (rcount != wcount || wcount == -1) {
  467. #if 0
  468. (void) fprintf(stderr, "#6\n");
  469. #endif
  470.             error(to.p_path);
  471.             break;
  472.         }
  473.     }
  474.     if (rcount < 0) {
  475. #if 0
  476. (void) fprintf(stderr, "#7\n");
  477. #endif
  478.         error(from.p_path);
  479.     }
  480.     if (pflag)
  481.         setfile(fs, to_fd);
  482.     /*
  483.      * If the source was setuid or setgid, lose the bits unless the
  484.      * copy is owned by the same user and group.
  485.      */
  486.     else if (fs->st_mode & (S_ISUID|S_ISGID) && fs->st_uid == myuid)
  487.         if (fstat(to_fd, &to_stat)) {
  488. #if 0
  489. (void) fprintf(stderr, "#8\n");
  490. #endif
  491.             error(to.p_path);
  492.         }
  493. #ifdef _POSIX_SOURCE /* DF_MSS */
  494. #define    RETAINBITS    (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
  495. #else
  496. #define    RETAINBITS    (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)
  497. #endif
  498. #ifdef _POSIX_SOURCE /* DF_MSS */
  499.         else if (fs->st_gid == to_stat.st_gid && chmod(to.p_path,
  500.             fs->st_mode & RETAINBITS & ~myumask)) {
  501. #else
  502.         else if (fs->st_gid == to_stat.st_gid && fchmod(to_fd,
  503.             fs->st_mode & RETAINBITS & ~myumask)) {
  504. #endif
  505. #if 0
  506. (void) fprintf(stderr, "#9\n");
  507. #endif
  508.             error(to.p_path);
  509.         }
  510.     (void)close(from_fd);
  511.     if (close(to_fd)) {
  512. #if 0
  513. (void) fprintf(stderr, "#10\n");
  514. #endif
  515.         error(to.p_path);
  516.     }
  517. }
  518.  
  519. void
  520. #if __STDC__
  521. copy_dir (void)
  522. #else
  523. copy_dir()
  524. #endif
  525. {
  526.     struct stat from_stat;
  527.     struct dirent *dp, **dir_list;
  528.     register int dir_cnt, i;
  529.     char *old_from, *old_to;
  530.  
  531.     dir_cnt = scandir(from.p_path, &dir_list, NULL, NULL);
  532.     if (dir_cnt == -1) {
  533.         (void)fprintf(stderr, "%s: can't read directory %s.\n",
  534.             progname, from.p_path);
  535.         exit_val = EXIT_FAILURE;
  536.     }
  537.  
  538.     /*
  539.      * Instead of handling directory entries in the order they appear
  540.      * on disk, do non-directory files before directory files.
  541.      * There are two reasons to do directories last.  The first is
  542.      * efficiency.  Files tend to be in the same cylinder group as
  543.      * their parent, whereas directories tend not to be.  Copying files
  544.      * all at once reduces seeking.  Second, deeply nested tree's
  545.      * could use up all the file descriptors if we didn't close one
  546.      * directory before recursivly starting on the next.
  547.      */
  548.     /* copy files */
  549.     for (i = 0; i < dir_cnt; ++i) {
  550.         dp = dir_list[i];
  551.  
  552. #ifdef _POSIX_SOURCE /* DF_MSS */
  553.                 if (strlen(dp->d_name) <= 2 && dp->d_name[0] == '.'
  554. #else
  555.                 if (dp->d_namlen <= 2 && dp->d_name[0] == '.'
  556. #endif
  557.             && (dp->d_name[1] == '\0' || dp->d_name[1] == '.'))
  558.             goto done;
  559. #ifdef _POSIX_SOURCE /* DF_MSS */
  560.         old_from = path_append(&from, dp->d_name, (int)strlen(dp->d_name));
  561. #else
  562.         old_from = path_append(&from, dp->d_name, (int)dp->d_namlen);
  563. #endif
  564.         if (!old_from) {
  565.             exit_val = EXIT_FAILURE;
  566.             goto done;
  567.         }
  568.  
  569.         if (statfcn(from.p_path, &from_stat) < 0) {
  570. #if 0
  571. (void) fprintf(stderr, "#11\n");
  572. #endif
  573.             error(dp->d_name);
  574.             path_restore(&from, old_from);
  575.             goto done;
  576.         }
  577.         if (S_ISDIR(from_stat.st_mode)) {
  578.             path_restore(&from, old_from);
  579.             continue;
  580.         }
  581.         old_to = path_append(&to, dp->d_name, (int)strlen(dp->d_name));
  582.         if (old_to) {
  583.             copy();
  584.             path_restore(&to, old_to);
  585.         } else
  586.             exit_val = EXIT_FAILURE;
  587.         path_restore(&from, old_from);
  588. done:        dir_list[i] = NULL;
  589.         (void)free((void *)dp);
  590.     }
  591.  
  592.     /* copy directories */
  593.     for (i = 0; i < dir_cnt; ++i) {
  594.         dp = dir_list[i];
  595.         if (!dp)
  596.             continue;
  597.         old_from = path_append(&from, dp->d_name, (int) strlen(dp->d_name));
  598.         if (!old_from) {
  599.             exit_val = EXIT_FAILURE;
  600.             (void)free((void *)dp);
  601.             continue;
  602.         }
  603.         old_to = path_append(&to, dp->d_name, (int) strlen(dp->d_name));
  604.         if (!old_to) {
  605.             exit_val = EXIT_FAILURE;
  606.             (void)free((void *)dp);
  607.             path_restore(&from, old_from);
  608.             continue;
  609.         }
  610.         copy();
  611.         free((void *)dp);
  612.         path_restore(&from, old_from);
  613.         path_restore(&to, old_to);
  614.     }
  615.     free((void *)dir_list);
  616. }
  617.  
  618. void
  619. #if __STDC__
  620. copy_link (int exists)
  621. #else
  622. copy_link(exists)
  623.     int exists;
  624. #endif
  625. {
  626. #ifdef _POSIX_SOURCE  /* DF_MSS */
  627.     if (exists)
  628.         ;
  629. #else
  630.     int len;
  631.     char link[MAXPATHLEN];
  632.  
  633.     if ((len = readlink(from.p_path, link, sizeof(link))) == -1) {
  634. #if 0
  635. (void) fprintf(stderr, "#12\n");
  636. #endif
  637.         error(from.p_path);
  638.         return;
  639.     }
  640.     link[len] = '\0';
  641.     if (exists && unlink(to.p_path)) {
  642. #if 0
  643. (void) fprintf(stderr, "#13\n");
  644. #endif
  645.         error(to.p_path);
  646.         return;
  647.     }
  648.     if (symlink(link, to.p_path)) {
  649. #if 0
  650. (void) fprintf(stderr, "#14\n");
  651. #endif
  652.         error(link);
  653.         return;
  654.     }
  655. #endif
  656. }
  657.  
  658. void
  659. #if __STDC__
  660. copy_fifo (struct stat *from_stat, int exists)
  661. #else
  662. copy_fifo(from_stat, exists)
  663.     struct stat *from_stat;
  664.     int exists;
  665. #endif
  666. {
  667.     if (exists && unlink(to.p_path)) {
  668. #if 0
  669. (void) fprintf(stderr, "#15\n");
  670. #endif
  671.         error(to.p_path);
  672.         return;
  673.     }
  674.     if (mkfifo(to.p_path, from_stat->st_mode)) {
  675. #if 0
  676. (void) fprintf(stderr, "#16\n");
  677. #endif
  678.         error(to.p_path);
  679.         return;
  680.     }
  681.     if (pflag)
  682.         setfile(from_stat, 0);
  683. }
  684.  
  685. void
  686. #if __STDC__
  687. copy_special (struct stat *from_stat, int exists)
  688. #else
  689. copy_special(from_stat, exists)
  690.     struct stat *from_stat;
  691.     int exists;
  692. #endif
  693. {
  694.     if (exists && unlink(to.p_path)) {
  695. #if 0
  696. (void) fprintf(stderr, "#17\n");
  697. #endif
  698.         error(to.p_path);
  699.         return;
  700.     }
  701. #ifdef _POSIX_SOURCE /* DF_MSS */
  702.     if (mknod(to.p_path, from_stat->st_mode, 0)) {
  703. #else
  704.     if (mknod(to.p_path, from_stat->st_mode, from_stat->st_rdev)) {
  705. #endif
  706. #if 0
  707. (void) fprintf(stderr, "#18\n");
  708. #endif
  709.         error(to.p_path);
  710.         return;
  711.     }
  712.     if (pflag)
  713.         setfile(from_stat, 0);
  714. }
  715.  
  716. void
  717. #if __STDC__
  718. setfile (register struct stat *fs, int fd)
  719. #else
  720. setfile(fs, fd)
  721.     register struct stat *fs;
  722.     int fd;
  723. #endif
  724. {
  725.     static struct timeval tv[2];
  726.     char path[100];
  727.  
  728. #ifdef _POSIX_SOURCE /* DF_MSS */
  729.     if (fd)
  730.         ;
  731. #endif
  732.     fs->st_mode &= S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO;
  733.  
  734.     tv[0].tv_sec = fs->st_atime;
  735.     tv[1].tv_sec = fs->st_mtime;
  736.     if (utimes(to.p_path, tv)) {
  737.         (void)snprintf(path, sizeof(path), "utimes: %s", to.p_path);
  738. #if 0
  739. (void) fprintf(stderr, "#19\n");
  740. #endif
  741.         error(path);
  742.     }
  743.     /*
  744.      * Changing the ownership probably won't succeed, unless we're root
  745.      * or POSIX_CHOWN_RESTRICTED is not set.  Set uid/gid before setting
  746.      * the mode; current BSD behavior is to remove all setuid bits on
  747.      * chown.  If chown fails, lose setuid/setgid bits.
  748.      */
  749. #ifdef _POSIX_SOURCE /* DF_MSS */
  750.     if (chown(to.p_path, fs->st_uid, fs->st_gid)) {
  751. #else
  752.     if (fd ? fchown(fd, fs->st_uid, fs->st_gid) :
  753.         chown(to.p_path, fs->st_uid, fs->st_gid)) {
  754. #endif
  755.         if (errno != EPERM) {
  756.             (void)snprintf(path, sizeof(path),
  757.                 "chown: %s", to.p_path);
  758. #if 0
  759. (void) fprintf(stderr, "#20\n");
  760. #endif
  761.             error(path);
  762.         }
  763.         fs->st_mode &= ~(S_ISUID|S_ISGID);
  764.     }
  765. #ifdef _POSIX_SOURCE /* DF_MSS */
  766.     if (chmod(to.p_path, fs->st_mode)) {
  767. #else
  768.     if (fd ? fchmod(fd, fs->st_mode) : chmod(to.p_path, fs->st_mode)) {
  769. #endif
  770.         (void)snprintf(path, sizeof(path), "chown: %s", to.p_path);
  771. #if 0
  772. (void) fprintf(stderr, "#21\n");
  773. #endif
  774.         error(path);
  775.     }
  776. }
  777.  
  778. void
  779. #if __STDC__
  780. error (const char *s)
  781. #else
  782. error(s)
  783.     char *s;
  784. #endif
  785. {
  786.     exit_val = EXIT_FAILURE;
  787.     (void)fprintf(stderr, "%s: %s: %s\n", progname, s, strerror(errno));
  788. }
  789.  
  790. void
  791. #if __STDC__
  792. usage (void)
  793. #else
  794. usage()
  795. #endif
  796. {
  797.     (void)fprintf(stderr,
  798. #if WIN_NT
  799. "usage: cp [-Rfip] src target;\n   or: cp [-Rfip] src1 ... srcN directory\n");
  800. #else
  801. "usage: cp [-Rfip] src target;\n   or: cp [-Rfhip] src1 ... srcN directory\n");
  802. #endif
  803. #if WIN_NT
  804.     if (ppid == (pid_t) 1 && globulation == 0)
  805.         deglobulate();
  806. #endif
  807.     exit(EXIT_FAILURE);
  808. }
  809.